package ICG;

import Common.*;
import Include.*;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

// 解析Go语言源代码 生成三地址代码
public class TrCodeGen implements GoParserListener {
    public int lineIndex;
    public int loaclIndex;
    public int ifIndex;
    public int forIndex;
    public Scope currentScope;
    public Map<String, Boolean> ptrs;
    public Scope globalScope;
    public String curFun;
    public List<Scope> allScope;
    public Map<RuleContext, String> values;
    public Map<RuleContext, String> ifvalues;
    public Map<RuleContext, ForStmt> forvalues;
    public Map<String, List<TACLine>> TACBlocks;
    public String TrCodeText;

    public TrCodeGen() {
        this.lineIndex = 0;
        this.loaclIndex = 0;
        this.ifIndex = 0;
        this.forIndex = 0;
        this.currentScope = new Scope();
        this.ptrs = new HashMap<>();
        this.globalScope = new Scope();
        this.curFun = "global";
        this.allScope = new ArrayList<Scope>();
        this.values = new HashMap<>();
        this.ifvalues = new HashMap<>();
        this.forvalues = new HashMap<>();
        this.TACBlocks = new HashMap<>();
        this.TrCodeText = "";
    }

    Type defineTmpType() {
        return Type.INT;
    }

    String CreateLocalVar() {
        boolean check = true;
        String local = "";
        Symbol res;
        while (check) {
            local = "T" + this.loaclIndex;
            this.loaclIndex += 1;
            res = this.currentScope.resolve(local);
            check = res != null;
        }
        return local;
    }

    String CreateElseLabel() {
        String local = "" + ifIndex;
        ifIndex++;
        return local;
    }

    String CreateForLabel() {
        String local = "" + forIndex;
        forIndex++;
        return local;
    }

    TacOperandType OperandTypereslove(String name) {
        if (this.ptrs.containsKey(name) && this.ptrs.get(name)) {
            return TacOperandType.PTR;
        }
        if (name.length() > 0 && (name.charAt(0) >= '0' && name.charAt(0) <= '9') || name.charAt(0) == '-') {
            return TacOperandType.IMM;
        }
        return TacOperandType.VAR;
    }

    boolean isDigit(String s) {
        String s1 = "";
        if (s.charAt(0) == '-') s1 = s.substring(1);
        for (int i = 0; i < s1.length(); i++) {
            if (!Character.isDigit(s1.charAt(i))) return false;
        }
        return true;
    }

    public void Go23file_(String filename) throws IOException {
        File file = new File(filename);
        if (!file.exists())
            file.createNewFile();
        FileWriter writer = new FileWriter(file);
        Set<String> keys = TACBlocks.keySet();
        for (String key : keys) {
            if (keys.size() > 0 && key.equals(keys.toArray()[0])) {
                continue; // 跳过第一个键
            }
            List<TACLine> blocks = TACBlocks.get(key);
            for (TACLine tacLine : blocks) {
                writer.append(tacLine.line + "\t" + tacLine.op.name + "\t" + tacLine.src1.value + "\t" + tacLine.src2.value + "\t" + tacLine.dst.value + "\n");
            }
            writer.append("----------------------\n");
        }
        writer.append("----------------------\n");
        writer.close();
    }

    void push_line(TacOp op, Operand src1, Operand src2, Operand dst) {
        TACLine curTACLine = new TACLine(lineIndex, op, src1, src2, dst, currentScope);
        this.TACBlocks.get(curFun).add(curTACLine);
        lineIndex++;
    }

    void myPrint(Scope scope) {
        Set<String> keys = scope.para_symbols.keySet();
        for (String key : keys) {
            System.out.println("para_symbol:" + key);
        }
        keys = scope.fun_symbols.keySet();
        for (String key : keys) {
            System.out.println("fun_symbol:" + key);
        }
    }

    void addScope() {
        Scope scope = new Scope(currentScope);
        this.allScope.add(scope);
        this.currentScope = scope;
    }

    void popScope() {
        myPrint(currentScope);
        if (currentScope.enclosingScope == null) {
            currentScope.enclosingScope = new Scope();
            currentScope.enclosingScope.fun_symbols = currentScope.fun_symbols;
            currentScope.enclosingScope.para_symbols = currentScope.para_symbols;
        }
        currentScope = currentScope.enclosingScope;
    }

    @Override
    public void enterSourceFile(GoParser.SourceFileContext ctx) {
        this.currentScope = this.globalScope;
        List<TACLine> curBlock = new ArrayList<>();
        this.TACBlocks.put(curFun, curBlock);
    }

    @Override
    public void exitSourceFile(GoParser.SourceFileContext ctx) {
        System.out.println("exit source file.");
    }

    @Override
    public void enterPackageClause(GoParser.PackageClauseContext ctx) {

    }

    @Override
    public void exitPackageClause(GoParser.PackageClauseContext ctx) {

    }

    @Override
    public void enterImportDecl(GoParser.ImportDeclContext ctx) {

    }

    @Override
    public void exitImportDecl(GoParser.ImportDeclContext ctx) {

    }

    @Override
    public void enterImportSpec(GoParser.ImportSpecContext ctx) {

    }

    @Override
    public void exitImportSpec(GoParser.ImportSpecContext ctx) {

    }

    @Override
    public void enterImportPath(GoParser.ImportPathContext ctx) {

    }

    @Override
    public void exitImportPath(GoParser.ImportPathContext ctx) {

    }

    @Override
    public void enterDeclaration(GoParser.DeclarationContext ctx) {

    }

    @Override
    public void exitDeclaration(GoParser.DeclarationContext ctx) {

    }

    @Override
    public void enterConstDecl(GoParser.ConstDeclContext ctx) {

    }

    @Override
    public void exitConstDecl(GoParser.ConstDeclContext ctx) {

    }

    @Override
    public void enterConstSpec(GoParser.ConstSpecContext ctx) {

    }

    @Override
    public void exitConstSpec(GoParser.ConstSpecContext ctx) {

    }

    @Override
    public void enterIdentifierList(GoParser.IdentifierListContext ctx) {

    }

    @Override
    public void exitIdentifierList(GoParser.IdentifierListContext ctx) {

    }

    @Override
    public void enterExpressionList(GoParser.ExpressionListContext ctx) {

    }

    @Override
    public void exitExpressionList(GoParser.ExpressionListContext ctx) {
        List<String> expression_values = new ArrayList<>();
        int len = ctx.expression().size();
        for (int i = 0; i < len; i++) {
            String s = this.values.get(ctx.expression(i));
            List<String> vs = Utils.ctx_decoder(s);
            for (String each : vs) {
                expression_values.add(each);
            }
        }
        this.values.put(ctx, Utils.ctx_encoder(expression_values));
    }

    @Override
    public void enterTypeDecl(GoParser.TypeDeclContext ctx) {

    }

    @Override
    public void exitTypeDecl(GoParser.TypeDeclContext ctx) {

    }

    @Override
    public void enterTypeSpec(GoParser.TypeSpecContext ctx) {

    }

    @Override
    public void exitTypeSpec(GoParser.TypeSpecContext ctx) {

    }

    @Override
    public void enterFunctionDecl(GoParser.FunctionDeclContext ctx) {
        String identifier = ctx.IDENTIFIER().getText();
        if (this.currentScope != null && this.currentScope.cur_resolve(identifier)) {
            System.out.println("Redeclaration of function" + identifier);
            System.exit(1);
        }
        this.curFun = identifier;

        int n;
        String eachType;
        Type type;
        List<TACLine> curBlock = new ArrayList<>();
        this.TACBlocks.put(this.curFun, curBlock);
        List<Type> funRetTypeList = new ArrayList<>();
        List<Type> funParaList = new ArrayList<>();

        if (ctx.signature().result() == null || ctx.signature().result().parameters().parameterDecl().size() == 0) {
            System.out.print("");
        } else {
            n = ctx.signature().result().parameters().parameterDecl().size();
            for (int i = 0; i < n; i++) {
                eachType = ctx.signature().result().parameters().parameterDecl(i).type_().typeName().getText();
                type = Symbol.toType(eachType);
                funRetTypeList.add(type);
            }
        }

        if (ctx.signature().parameters().parameterDecl().size() == 0) {
            System.out.print("");
        } else {
            n = ctx.signature().parameters().parameterDecl().size();
            for (int i = 0; i < n; i++) {
                eachType = ctx.signature().parameters().parameterDecl(i).type_().typeName().getText();
                type = Symbol.toType(eachType);
                for (int j = 0; j < ctx.signature().parameters().parameterDecl(i).identifierList().IDENTIFIER().size(); j++) {
                    funParaList.add(type);
                }
            }
        }

        Symbol symbol = new Symbol(identifier, this.currentScope, SymbolType.FUN, null, funRetTypeList, funParaList, false, 0);
        Scope scope = new Scope(this.currentScope);
        if (this.currentScope == null) {
            this.currentScope = new Scope();
        }
        this.currentScope.fun_define(symbol);
        this.currentScope = scope;

        for (int i = 0; i < ctx.signature().parameters().parameterDecl().size(); i++) {
            for (int j = 0; j < ctx.signature().parameters().parameterDecl(i).identifierList().IDENTIFIER().size(); j++) {
                String fun_para = ctx.signature().parameters().parameterDecl(i).identifierList().IDENTIFIER(j).getText();
                this.push_line(TacOp.FUN_PARA, new Operand(fun_para, this.OperandTypereslove(fun_para)), new Operand("", TacOperandType.NULL_), new Operand("", TacOperandType.NULL_));
            }
        }
    }

    @Override
    public void exitFunctionDecl(GoParser.FunctionDeclContext ctx) {
        this.curFun = "global";
        this.popScope();
    }

    @Override
    public void enterMethodDecl(GoParser.MethodDeclContext ctx) {

    }

    @Override
    public void exitMethodDecl(GoParser.MethodDeclContext ctx) {

    }

    @Override
    public void enterReceiver(GoParser.ReceiverContext ctx) {

    }

    @Override
    public void exitReceiver(GoParser.ReceiverContext ctx) {

    }

    @Override
    public void enterVarDecl(GoParser.VarDeclContext ctx) {

    }

    @Override
    public void exitVarDecl(GoParser.VarDeclContext ctx) {

    }

    @Override
    public void enterVarSpec(GoParser.VarSpecContext ctx) {

    }

    @Override
    public void exitVarSpec(GoParser.VarSpecContext ctx) {
        boolean is_array = false;
        int array_length = 0;
        List<String> right_values;
        if (ctx.type_() != null && ctx.type_().typeLit() != null) {
            is_array = true;
            right_values = Utils.ctx_decoder(this.values.get(ctx.type_().typeLit().arrayType().arrayLength().expression()));
            if (right_values.size() != 1) {
                System.out.println("wrong number of array length input.");
                System.exit(1);
            }
            String array_length_s = right_values.get(0);
            if (this.isDigit(array_length_s)) {
                array_length = Integer.valueOf(array_length_s);
                if (array_length < 1) {
                    System.out.println("array length should >= 1.");
                    System.exit(1);
                }
            } else {
                System.out.println("array declaration need static capacity");
                System.exit(1);
            }
        }
        int n = ctx.identifierList().IDENTIFIER().size();
        String varname;
        Type type = null;
        for (int i = 0; i < n; i++) {
            varname = ctx.identifierList().IDENTIFIER(i).getText();
            if (ctx.type_() == null) type = this.defineTmpType();
            else {
                if (ctx.type_().typeName() != null) {
                    type = Symbol.toType(ctx.type_().typeName().getText());
                } else if (ctx.type_().typeLit() != null && ctx.type_().typeLit().arrayType() != null) {
                    type = Symbol.toType(ctx.type_().typeLit().arrayType().elementType().getText());
                }
            }

            if (this.currentScope.cur_resolve(varname)) {
                System.out.println("Redeclaration of parameter" + varname + "");
                System.exit(1);
            }

            Symbol symbol = new Symbol(varname, currentScope, SymbolType.VAR, type, null, null, is_array, array_length);
            if (is_array) {
                this.push_line(TacOp.CREATLIST,
                        new Operand(varname, this.OperandTypereslove(varname)),
                        new Operand("" + array_length, this.OperandTypereslove("" + array_length)),
                        new Operand("INT", TacOperandType.NULL_));
            }
            this.currentScope.para_define(symbol);
        }

        if (ctx.expressionList() != null) {
            right_values = Utils.ctx_decoder(this.values.get(ctx.expressionList()));
            if (n != right_values.size()) {
                System.out.println("wrong number matched.");
                System.exit(1);
            }
            for (int i = 0; i < n; i++) {
                push_line(TacOp.ASSIGN,
                        new Operand(right_values.get(i), this.OperandTypereslove(right_values.get(i))),
                        new Operand("", TacOperandType.NULL_),
                        new Operand(ctx.identifierList().IDENTIFIER(i).getText(), this.OperandTypereslove(ctx.identifierList().IDENTIFIER(i).getText())));
            }
        }

    }

    @Override
    public void enterBlock(GoParser.BlockContext ctx) {
        if (ctx.parent.getChild(0).getText().equals("for")) {
            push_line(TacOp.LABEL,
                    new Operand("FORLOOP" + forvalues.get(ctx.parent).CurIndex, TacOperandType.LABEL),
                    new Operand("", TacOperandType.NULL_),
                    new Operand("", TacOperandType.NULL_));
        }

        if (ctx.parent.getChildCount() >= 5 && ctx.parent.getChild(4).equals(ctx) && ctx.parent.getChild(3).getText().equals("else")) {
            push_line(TacOp.LABEL,
                    new Operand("ELSE" + ifvalues.get(ctx.parent), TacOperandType.LABEL),
                    new Operand("", TacOperandType.NULL_),
                    new Operand("", TacOperandType.NULL_));
        }
        addScope();
    }

    @Override
    public void exitBlock(GoParser.BlockContext ctx) {
        if (ctx.parent.getChild(0).getText().equals("for")) {
            ForStmt forStmt = forvalues.get(ctx.parent);
            TACLine updateCondition = forStmt.UpdateCon;
            TACLine loopCondition = forStmt.LoopCon;
            if (updateCondition != null) {
                push_line(updateCondition.op, updateCondition.src1, updateCondition.src2, updateCondition.dst);
            }
            if (loopCondition != null) {
                push_line(loopCondition.op, loopCondition.src1, loopCondition.src2, loopCondition.dst);
            }
        }
        if (ctx.parent.getChildCount() > 2 && ctx.parent.getChild(2).equals(ctx) && ctx.parent.getChild(0).getText().equals("if")) {
            push_line(TacOp.GOTO,
                    new Operand("ENDIF" + ifvalues.get(ctx.parent), TacOperandType.LABEL),
                    new Operand("", TacOperandType.NULL_),
                    new Operand("", TacOperandType.NULL_));
        }
        popScope();
    }

    @Override
    public void enterStatementList(GoParser.StatementListContext ctx) {

    }

    @Override
    public void exitStatementList(GoParser.StatementListContext ctx) {

    }

    @Override
    public void enterStatement(GoParser.StatementContext ctx) {

    }

    @Override
    public void exitStatement(GoParser.StatementContext ctx) {

    }

    @Override
    public void enterSimpleStmt(GoParser.SimpleStmtContext ctx) {

    }

    @Override
    public void exitSimpleStmt(GoParser.SimpleStmtContext ctx) {

    }

    @Override
    public void enterExpressionStmt(GoParser.ExpressionStmtContext ctx) {

    }

    @Override
    public void exitExpressionStmt(GoParser.ExpressionStmtContext ctx) {

    }

    @Override
    public void enterSendStmt(GoParser.SendStmtContext ctx) {

    }

    @Override
    public void exitSendStmt(GoParser.SendStmtContext ctx) {

    }

    @Override
    public void enterIncDecStmt(GoParser.IncDecStmtContext ctx) {

    }

    @Override
    public void exitIncDecStmt(GoParser.IncDecStmtContext ctx) {
        if (ctx.getChild(1).getText().equals("++")) {
            List<String> left_values;
            left_values = Utils.ctx_decoder(values.get(ctx.expression()));
            if (left_values.size() != 1) {
                System.out.println("too many parameter for incdec \"++\" ");
                System.exit(1);
            }
            String varname, varvalue;
            if (ctx.parent.parent.parent.getChild(0).getText().equals("for") && ctx.parent.parent.equals(ctx.parent.parent.parent.getChild(1))) {
                varname = left_values.get(0);
                varvalue = "1";
                ForStmt forStmt = forvalues.get(ctx.parent.parent.parent);
                TACLine tmpline = new TACLine(lineIndex, TacOp.ADD,
                        new Operand(varname, OperandTypereslove(varname)),
                        new Operand(varvalue, OperandTypereslove(varvalue)),
                        new Operand(varname, OperandTypereslove(varname)),
                        currentScope);
                forStmt.UpdateCon = tmpline;
            } else {
                varname = left_values.get(0);
                varvalue = "1";
                push_line(TacOp.ADD,
                        new Operand(varname, OperandTypereslove(varname)),
                        new Operand(varvalue, OperandTypereslove(varvalue)),
                        new Operand(varname, OperandTypereslove(varname)));
            }
        }
    }

    @Override
    public void enterAssignment(GoParser.AssignmentContext ctx) {

    }

    @Override
    public void exitAssignment(GoParser.AssignmentContext ctx) {
        List<String> left_values;
        List<String> right_values;
        String varname, varvalue;
        if (ctx.assign_op().getText().equals("=")) {
            left_values = Utils.ctx_decoder(values.get(ctx.expressionList(0)));
            right_values = Utils.ctx_decoder(values.get(ctx.expressionList(1)));
            if (left_values.size() != right_values.size()) {
                System.out.println("not equal number parameter for assign \"=\"");
                System.exit(1);
            }
            for (int i = 0; i < left_values.size(); i++) {
                varname = left_values.get(i);
                varvalue = right_values.get(i);
                push_line(TacOp.ASSIGN,
                        new Operand(varvalue, OperandTypereslove(varvalue)),
                        new Operand("", TacOperandType.NULL_),
                        new Operand(varname, OperandTypereslove(varname)));
            }
        }

        if (ctx.assign_op().getText().equals("+=")) {
            left_values = Utils.ctx_decoder(values.get(ctx.expressionList(0)));
            right_values = Utils.ctx_decoder(values.get(ctx.expressionList(1)));
            if (left_values.size() != right_values.size()) {
                System.out.println("too many parameter for assign \"+=\"");
                System.exit(1);
            }
            if (ctx.parent.parent.parent.getChild(0).getText().equals("for")
                    && ctx.parent.parent.equals(ctx.parent.parent.parent.getChild(1))) {
                varname = left_values.get(0);
                varvalue = right_values.get(0);
                ForStmt forStmt = forvalues.get(ctx.parent.parent.parent);
                TACLine tmpline = new TACLine(lineIndex, TacOp.ADD,
                        new Operand(varname, OperandTypereslove(varname)),
                        new Operand(varvalue, OperandTypereslove(varvalue)),
                        new Operand(varname, OperandTypereslove(varname)),
                        currentScope);
                forStmt.UpdateCon = tmpline;
                this.forvalues.put(ctx.parent.parent.getParent(), forStmt);
            } else {
                varname = left_values.get(0);
                varvalue = right_values.get(0);
                push_line(TacOp.ADD,
                        new Operand(varname, OperandTypereslove(varname)),
                        new Operand(varvalue, OperandTypereslove(varvalue)),
                        new Operand(varname, OperandTypereslove(varname)));
            }
        }
    }

    @Override
    public void enterAssign_op(GoParser.Assign_opContext ctx) {

    }

    @Override
    public void exitAssign_op(GoParser.Assign_opContext ctx) {

    }

    @Override
    public void enterShortVarDecl(GoParser.ShortVarDeclContext ctx) {

    }

    @Override
    public void exitShortVarDecl(GoParser.ShortVarDeclContext ctx) {
        int n = ctx.identifierList().IDENTIFIER().size();
        List<String> left_values;
        List<String> right_values;
        String varname, varvalue;
        Type type;

        for (int i = 0; i < n; i++) {
            varname = ctx.identifierList().IDENTIFIER(i).getText();
            type = defineTmpType();
            Symbol symbol = new Symbol(varname, currentScope, SymbolType.VAR, type, null, null, false, 0);
            currentScope.para_define(symbol);
        }

        if (ctx.expressionList() != null) {
            right_values = Utils.ctx_decoder(values.get(ctx.expressionList()));
            if (n != right_values.size()) {
                System.out.println("wrong number match.");
                System.exit(1);
            }
            for (int i = 0; i < n; i++) {
                push_line(TacOp.ASSIGN,
                        new Operand(right_values.get(i), OperandTypereslove(right_values.get(i))),
                        new Operand("", TacOperandType.NULL_),
                        new Operand(ctx.identifierList().IDENTIFIER(i).getText(), OperandTypereslove(ctx.identifierList().IDENTIFIER(i).getText())));
            }
        }

        if (ctx.parent.parent.parent.getChild(0).getText().equals("for") && ctx.parent.parent.parent.getChild(1).equals(ctx.parent.parent)) {
            ForStmt tmp = forvalues.get(ctx.parent.parent.parent);
            for (int i = 0; i < n; i++) {
                varname = ctx.identifierList().IDENTIFIER(i).getText();
                tmp.newParas.add(varname);
            }
            forvalues.put(ctx.parent.parent.parent, tmp);
        }
    }

    @Override
    public void enterEmptyStmt(GoParser.EmptyStmtContext ctx) {

    }

    @Override
    public void exitEmptyStmt(GoParser.EmptyStmtContext ctx) {

    }

    @Override
    public void enterLabeledStmt(GoParser.LabeledStmtContext ctx) {

    }

    @Override
    public void exitLabeledStmt(GoParser.LabeledStmtContext ctx) {

    }

    @Override
    public void enterReturnStmt(GoParser.ReturnStmtContext ctx) {

    }

    @Override
    public void exitReturnStmt(GoParser.ReturnStmtContext ctx) {
        List<String> return_values = Utils.ctx_decoder(values.get(ctx.expressionList()));
        for (String i : return_values) {
            Symbol tmp = currentScope.resolve(i);
            if (tmp == null) {
                System.out.println("Undefined" + i);
                System.exit(1);
            }
        }
        for (String i : return_values) {
            push_line(TacOp.FUN_PARA,
                    new Operand(i, OperandTypereslove(i)),
                    new Operand("", TacOperandType.NULL_),
                    new Operand("", TacOperandType.NULL_));
        }
    }

    @Override
    public void enterBreakStmt(GoParser.BreakStmtContext ctx) {

    }

    @Override
    public void exitBreakStmt(GoParser.BreakStmtContext ctx) {

    }

    @Override
    public void enterContinueStmt(GoParser.ContinueStmtContext ctx) {

    }

    @Override
    public void exitContinueStmt(GoParser.ContinueStmtContext ctx) {

    }

    @Override
    public void enterGotoStmt(GoParser.GotoStmtContext ctx) {

    }

    @Override
    public void exitGotoStmt(GoParser.GotoStmtContext ctx) {

    }

    @Override
    public void enterFallthroughStmt(GoParser.FallthroughStmtContext ctx) {

    }

    @Override
    public void exitFallthroughStmt(GoParser.FallthroughStmtContext ctx) {

    }

    @Override
    public void enterDeferStmt(GoParser.DeferStmtContext ctx) {

    }

    @Override
    public void exitDeferStmt(GoParser.DeferStmtContext ctx) {

    }

    @Override
    public void enterIfStmt(GoParser.IfStmtContext ctx) {
        String iftmp = CreateElseLabel();
        ifvalues.put(ctx, iftmp);
    }

    @Override
    public void exitIfStmt(GoParser.IfStmtContext ctx) {
        push_line(TacOp.LABEL,
                new Operand("ENDIF" + ifvalues.get(ctx), TacOperandType.LABEL),
                new Operand("", TacOperandType.NULL_),
                new Operand("", TacOperandType.NULL_));
    }

    @Override
    public void enterSwitchStmt(GoParser.SwitchStmtContext ctx) {

    }

    @Override
    public void exitSwitchStmt(GoParser.SwitchStmtContext ctx) {

    }

    @Override
    public void enterExprSwitchStmt(GoParser.ExprSwitchStmtContext ctx) {

    }

    @Override
    public void exitExprSwitchStmt(GoParser.ExprSwitchStmtContext ctx) {

    }

    @Override
    public void enterExprCaseClause(GoParser.ExprCaseClauseContext ctx) {

    }

    @Override
    public void exitExprCaseClause(GoParser.ExprCaseClauseContext ctx) {

    }

    @Override
    public void enterExprSwitchCase(GoParser.ExprSwitchCaseContext ctx) {

    }

    @Override
    public void exitExprSwitchCase(GoParser.ExprSwitchCaseContext ctx) {

    }

    @Override
    public void enterTypeSwitchStmt(GoParser.TypeSwitchStmtContext ctx) {

    }

    @Override
    public void exitTypeSwitchStmt(GoParser.TypeSwitchStmtContext ctx) {

    }

    @Override
    public void enterTypeSwitchGuard(GoParser.TypeSwitchGuardContext ctx) {

    }

    @Override
    public void exitTypeSwitchGuard(GoParser.TypeSwitchGuardContext ctx) {

    }

    @Override
    public void enterTypeCaseClause(GoParser.TypeCaseClauseContext ctx) {

    }

    @Override
    public void exitTypeCaseClause(GoParser.TypeCaseClauseContext ctx) {

    }

    @Override
    public void enterTypeSwitchCase(GoParser.TypeSwitchCaseContext ctx) {

    }

    @Override
    public void exitTypeSwitchCase(GoParser.TypeSwitchCaseContext ctx) {

    }

    @Override
    public void enterTypeList(GoParser.TypeListContext ctx) {

    }

    @Override
    public void exitTypeList(GoParser.TypeListContext ctx) {

    }

    @Override
    public void enterSelectStmt(GoParser.SelectStmtContext ctx) {

    }

    @Override
    public void exitSelectStmt(GoParser.SelectStmtContext ctx) {

    }

    @Override
    public void enterCommClause(GoParser.CommClauseContext ctx) {

    }

    @Override
    public void exitCommClause(GoParser.CommClauseContext ctx) {

    }

    @Override
    public void enterCommCase(GoParser.CommCaseContext ctx) {

    }

    @Override
    public void exitCommCase(GoParser.CommCaseContext ctx) {

    }

    @Override
    public void enterRecvStmt(GoParser.RecvStmtContext ctx) {

    }

    @Override
    public void exitRecvStmt(GoParser.RecvStmtContext ctx) {

    }

    @Override
    public void enterForStmt(GoParser.ForStmtContext ctx) {
        String tmp = CreateForLabel();
        ForStmt newfor = new ForStmt(tmp);
        forvalues.put(ctx, newfor);
        addScope();
    }

    @Override
    public void exitForStmt(GoParser.ForStmtContext ctx) {
        ForStmt tmp = forvalues.get(ctx);
        popScope();
        push_line(TacOp.LABEL,
                new Operand("ENDFOR" + forvalues.get(ctx).CurIndex, TacOperandType.LABEL),
                new Operand("", TacOperandType.NULL_),
                new Operand("", TacOperandType.NULL_));

    }

    @Override
    public void enterForClause(GoParser.ForClauseContext ctx) {

    }

    @Override
    public void exitForClause(GoParser.ForClauseContext ctx) {

    }

    @Override
    public void enterRangeClause(GoParser.RangeClauseContext ctx) {

    }

    @Override
    public void exitRangeClause(GoParser.RangeClauseContext ctx) {

    }

    @Override
    public void enterGoStmt(GoParser.GoStmtContext ctx) {

    }

    @Override
    public void exitGoStmt(GoParser.GoStmtContext ctx) {

    }

    @Override
    public void enterType_(GoParser.Type_Context ctx) {

    }

    @Override
    public void exitType_(GoParser.Type_Context ctx) {

    }

    @Override
    public void enterTypeName(GoParser.TypeNameContext ctx) {

    }

    @Override
    public void exitTypeName(GoParser.TypeNameContext ctx) {

    }

    @Override
    public void enterTypeLit(GoParser.TypeLitContext ctx) {

    }

    @Override
    public void exitTypeLit(GoParser.TypeLitContext ctx) {

    }

    @Override
    public void enterArrayType(GoParser.ArrayTypeContext ctx) {

    }

    @Override
    public void exitArrayType(GoParser.ArrayTypeContext ctx) {

    }

    @Override
    public void enterArrayLength(GoParser.ArrayLengthContext ctx) {

    }

    @Override
    public void exitArrayLength(GoParser.ArrayLengthContext ctx) {

    }

    @Override
    public void enterElementType(GoParser.ElementTypeContext ctx) {

    }

    @Override
    public void exitElementType(GoParser.ElementTypeContext ctx) {

    }

    @Override
    public void enterPointerType(GoParser.PointerTypeContext ctx) {

    }

    @Override
    public void exitPointerType(GoParser.PointerTypeContext ctx) {

    }

    @Override
    public void enterInterfaceType(GoParser.InterfaceTypeContext ctx) {

    }

    @Override
    public void exitInterfaceType(GoParser.InterfaceTypeContext ctx) {

    }

    @Override
    public void enterSliceType(GoParser.SliceTypeContext ctx) {

    }

    @Override
    public void exitSliceType(GoParser.SliceTypeContext ctx) {

    }

    @Override
    public void enterMapType(GoParser.MapTypeContext ctx) {

    }

    @Override
    public void exitMapType(GoParser.MapTypeContext ctx) {

    }

    @Override
    public void enterChannelType(GoParser.ChannelTypeContext ctx) {

    }

    @Override
    public void exitChannelType(GoParser.ChannelTypeContext ctx) {

    }

    @Override
    public void enterMethodSpec(GoParser.MethodSpecContext ctx) {

    }

    @Override
    public void exitMethodSpec(GoParser.MethodSpecContext ctx) {

    }

    @Override
    public void enterFunctionType(GoParser.FunctionTypeContext ctx) {

    }

    @Override
    public void exitFunctionType(GoParser.FunctionTypeContext ctx) {

    }

    @Override
    public void enterSignature(GoParser.SignatureContext ctx) {

    }

    @Override
    public void exitSignature(GoParser.SignatureContext ctx) {

    }

    @Override
    public void enterResult(GoParser.ResultContext ctx) {

    }

    @Override
    public void exitResult(GoParser.ResultContext ctx) {

    }

    @Override
    public void enterParameters(GoParser.ParametersContext ctx) {

    }

    @Override
    public void exitParameters(GoParser.ParametersContext ctx) {

    }

    @Override
    public void enterParameterDecl(GoParser.ParameterDeclContext ctx) {
        if (ctx.identifierList() != null) {
            int n = ctx.identifierList().IDENTIFIER().size();
            for (int i = 0; i < n; i++) {
                String integer = ctx.identifierList().IDENTIFIER(i).getText();
                String stype = ctx.type_().typeName().getText();
                Type type = Symbol.toType(stype);
                Symbol symbol = new Symbol(integer, currentScope, SymbolType.VAR, type);
                currentScope.para_define(symbol);
            }
        }
    }

    @Override
    public void exitParameterDecl(GoParser.ParameterDeclContext ctx) {

    }

    @Override
    public void enterLogicalAndOperation(GoParser.LogicalAndOperationContext ctx) {

    }

    @Override
    public void exitLogicalAndOperation(GoParser.LogicalAndOperationContext ctx) {

    }

    @Override
    public void enterUnaryOperation(GoParser.UnaryOperationContext ctx) {

    }

    @Override
    public void exitUnaryOperation(GoParser.UnaryOperationContext ctx) {

    }

    @Override
    public void enterPrimaryExpression(GoParser.PrimaryExpressionContext ctx) {

    }

    @Override
    public void exitPrimaryExpression(GoParser.PrimaryExpressionContext ctx) {
        String ExVl = values.get(ctx.primaryExpr());
        values.put(ctx, ExVl);
    }

    @Override
    public void enterPlusMinusOperation(GoParser.PlusMinusOperationContext ctx) {

    }

    @Override
    public void exitPlusMinusOperation(GoParser.PlusMinusOperationContext ctx) {
        List<String> left_values = Utils.ctx_decoder(values.get(ctx.expression(0)));
        List<String> right_values = Utils.ctx_decoder(values.get(ctx.expression(1)));
        if (left_values.size() != 1 || right_values.size() != 1) {
            System.out.println("wrong literal number1 ");
            System.exit(1);
        }
        String dst = CreateLocalVar();
        List<String> pv = new ArrayList<>();
        pv.add(dst);

        if (ctx.PLUS() != null) {
            push_line(TacOp.ADD,
                    new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                    new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                    new Operand(dst, OperandTypereslove(dst)));
        } else if (ctx.MINUS() != null) {
            push_line(TacOp.SUB,
                    new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                    new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                    new Operand(dst, OperandTypereslove(dst)));
        }
        values.put(ctx, Utils.ctx_encoder(pv));
    }

    @Override
    public void enterRelationOperation(GoParser.RelationOperationContext ctx) {

    }

    @Override
    public void exitRelationOperation(GoParser.RelationOperationContext ctx) {
        List<String> left_values = Utils.ctx_decoder(values.get(ctx.expression(0)));
        List<String> right_values = Utils.ctx_decoder(values.get(ctx.expression(1)));
        if (left_values.size() != 1 || right_values.size() != 1) {
            System.out.println("wrong literal number2.");
            System.exit(1);
        }
        if (ctx.parent.parent.getChild(0).getText().equals("for") && ctx.parent.parent.getChild(1).equals(ctx.parent)) {
            ForStmt tmp = forvalues.get(ctx.parent.parent);
            String dst = "ENDFOR" + tmp.CurIndex;
            String dst_ = "FORLOOP" + tmp.CurIndex;
            TACLine tmpline = new TACLine();
            if (ctx.EQUALS() != null) {
                tmpline = new TACLine(lineIndex, TacOp.IFEQ,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst_, TacOperandType.LABEL), currentScope);
                push_line(TacOp.IFNEQ,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst, TacOperandType.LABEL));
            } else if (ctx.GREATER() != null) {
                tmpline = new TACLine(lineIndex, TacOp.IFGE,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst_, TacOperandType.LABEL), currentScope);
                push_line(TacOp.IFLT,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst, TacOperandType.LABEL));
            } else if (ctx.LESS() != null) {
                tmpline = new TACLine(lineIndex, TacOp.IFLT,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst_, TacOperandType.LABEL), currentScope);
                push_line(TacOp.IFGE,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst, TacOperandType.LABEL));
            } else if (ctx.LESS_OR_EQUALS() != null) {
                tmpline = new TACLine(lineIndex, TacOp.IFLE,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst_, TacOperandType.LABEL), currentScope);
                push_line(TacOp.IFGT,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst, TacOperandType.LABEL));
            }
            tmp.LoopCon = tmpline;
            forvalues.put(ctx.parent.parent, tmp);
        }

        if (ctx.parent.getText().contains("if") && ctx.equals(ctx.parent.getChild(1))) {
            String dst;
            if (ctx.parent.getText().contains("else")) {
                dst = "ELSE" + ifvalues.get(ctx.parent);
            } else dst = "ENDIF" + ifvalues.get(ctx.parent);
            if (ctx.EQUALS() != null) {
                push_line(TacOp.IFNEQ,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst, TacOperandType.LABEL));
            } else if (ctx.NOT_EQUALS() != null) {
                push_line(TacOp.IFEQ,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst, TacOperandType.LABEL));
            } else if (ctx.GREATER() != null) {
                push_line(TacOp.IFLE,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst, TacOperandType.LABEL));
            } else if (ctx.GREATER_OR_EQUALS() != null) {
                push_line(TacOp.IFLT,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst, TacOperandType.LABEL));
            } else if (ctx.LESS() != null) {
                push_line(TacOp.IFGE,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst, TacOperandType.LABEL));
            } else if (ctx.LESS_OR_EQUALS() != null) {
                push_line(TacOp.IFGT,
                        new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                        new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                        new Operand(dst, TacOperandType.LABEL));
            }
        }

    }

    @Override
    public void enterMulDivOperation(GoParser.MulDivOperationContext ctx) {

    }

    @Override
    public void exitMulDivOperation(GoParser.MulDivOperationContext ctx) {
        List<String> left_values = Utils.ctx_decoder(values.get(ctx.expression(0)));
        List<String> right_values = Utils.ctx_decoder(values.get(ctx.expression(1)));
        if (left_values.size() != 1 || right_values.size() != 1) {
            System.out.println("wrong literal number2.");
            System.exit(1);
        }
        String dst = CreateLocalVar();
        List<String> mov = new ArrayList<>();
        mov.add(dst);
        if (ctx.STAR() != null) {
            push_line(TacOp.MUL, new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                    new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                    new Operand(dst, OperandTypereslove(dst)));
        } else if (ctx.DIV() != null) {
            push_line(TacOp.DIV, new Operand(left_values.get(0), OperandTypereslove(left_values.get(0))),
                    new Operand(right_values.get(0), OperandTypereslove(right_values.get(0))),
                    new Operand(dst, OperandTypereslove(dst)));

        }
        values.put(ctx, Utils.ctx_encoder(mov));
    }

    @Override
    public void enterLogicalOrOperation(GoParser.LogicalOrOperationContext ctx) {

    }

    @Override
    public void exitLogicalOrOperation(GoParser.LogicalOrOperationContext ctx) {

    }

    @Override
    public void enterPrimaryExpr(GoParser.PrimaryExprContext ctx) {

    }

    @Override
    public void exitPrimaryExpr(GoParser.PrimaryExprContext ctx) {
        if (ctx.arguments() != null) {
            List<String> pev = new ArrayList<>();
            List<String> fun_id = Utils.ctx_decoder(values.get(ctx.primaryExpr()));
            System.out.println("function: "+ctx.primaryExpr().getText());
            String s = fun_id.get(0);
            Symbol fun_sym;
            fun_sym = currentScope.resolve(s);
            if (fun_sym == null) {
                System.out.println("Undifined Function:" + s);
                System.exit(1);
            }
            List<String> args = Utils.ctx_decoder(values.get(ctx.arguments()));
            if (fun_sym.fun_para_type_list != null && fun_sym.fun_para_type_list.size() != args.size()) {
                System.out.println("Undifined Function:" + s);
                System.exit(1);
            }
            String blank = "";
            for (Type t : fun_sym.fun_para_type_list) {
                String tmp = CreateLocalVar();
                push_line(TacOp.RET,
                        new Operand(tmp, OperandTypereslove(tmp)),
                        new Operand(blank, TacOperandType.NULL_),
                        new Operand(blank, TacOperandType.NULL_));
                pev.add(tmp);
            }
            for (String arg : args) {
                push_line(TacOp.PARA,
                        new Operand(arg, OperandTypereslove(arg)),
                        new Operand(blank, TacOperandType.NULL_),
                        new Operand(blank, TacOperandType.NULL_));
            }
            push_line(TacOp.CALL,
                    new Operand(s, OperandTypereslove(s)),
                    new Operand(blank, TacOperandType.NULL_),
                    new Operand(blank, TacOperandType.NULL_));
            values.put(ctx, Utils.ctx_encoder(pev));
        } else if (ctx.operand() != null) {
            String v = values.get(ctx.operand());
            values.put(ctx, v);
        } else if (ctx.index() != null) {
            List<String> array_name = Utils.ctx_decoder(values.get(ctx.primaryExpr()));
            String id = array_name.get(0);
            Symbol arr_sym = currentScope.resolve(id);
            // TODO sym.name
            System.out.println(arr_sym.name);
            if (!arr_sym.is_array) {
                System.out.println("Only array can be indexed: " + id);
                System.exit(1);
            }
            List<String> array_index = Utils.ctx_decoder(values.get(ctx.index().expression()));
            String in = array_index.get(0);
            if (array_index.size() != 1) {
                int idx = Integer.valueOf(in);
                if (idx > arr_sym.array_length - 1 || idx < 0) {
                    System.out.println("Array index out of bound: " + id);
                    System.out.println(idx + " " + arr_sym.array_length);
                    System.exit(1);
                }
            }
            String tmp = CreateLocalVar();
            push_line(TacOp.MUL,
                    new Operand(Common.INT_SIZE, OperandTypereslove(Common.INT_SIZE)),
                    new Operand(in, OperandTypereslove(in)),
                    new Operand(tmp, OperandTypereslove(tmp)));
            String tm = CreateLocalVar();
            push_line(TacOp.ADD,
                    new Operand(id, OperandTypereslove(id)),
                    new Operand(tmp, OperandTypereslove(tmp)),
                    new Operand(tm, OperandTypereslove(tm)));
            ptrs.put(tm, true);
            values.put(ctx, tm);
        }
    }

    @Override
    public void enterConversion(GoParser.ConversionContext ctx) {

    }

    @Override
    public void exitConversion(GoParser.ConversionContext ctx) {

    }

    @Override
    public void enterNonNamedType(GoParser.NonNamedTypeContext ctx) {

    }

    @Override
    public void exitNonNamedType(GoParser.NonNamedTypeContext ctx) {

    }

    @Override
    public void enterOperand(GoParser.OperandContext ctx) {

    }

    @Override
    public void exitOperand(GoParser.OperandContext ctx) {
        String s = "";
        if (ctx.literal() != null) {
            s = values.get(ctx.literal());
            values.put(ctx, s);
        }
        if (ctx.expression() != null) {
            s = values.get(ctx.expression());
            values.put(ctx, s);
        }
        if (ctx.operandName() != null) {
            s = values.get(ctx.operandName());
            values.put(ctx, s);
        }
    }

    @Override
    public void enterLiteral(GoParser.LiteralContext ctx) {

    }

    @Override
    public void exitLiteral(GoParser.LiteralContext ctx) {
        if (ctx.basicLit() != null) {
            String bv = values.get(ctx.basicLit());
            values.put(ctx, bv);
        }
    }

    @Override
    public void enterBasicLit(GoParser.BasicLitContext ctx) {

    }

    @Override
    public void exitBasicLit(GoParser.BasicLitContext ctx) {
        if (ctx.integer() != null) {
            String bv = values.get(ctx.integer());
            values.put(ctx, bv);
        }
    }

    @Override
    public void enterInteger(GoParser.IntegerContext ctx) {

    }

    @Override
    public void exitInteger(GoParser.IntegerContext ctx) {
        values.put(ctx, ctx.DECIMAL_LIT().getText());
    }

    @Override
    public void enterOperandName(GoParser.OperandNameContext ctx) {

    }

    @Override
    public void exitOperandName(GoParser.OperandNameContext ctx) {
        System.out.println(ctx.IDENTIFIER().getText()+" " +currentScope.resolve(ctx.IDENTIFIER().getText()));
        if (currentScope.resolve(ctx.IDENTIFIER().getText()) == null) {
            System.out.println("Undefined Operand " + ctx.IDENTIFIER().getText());
            System.exit(1);
        }
        values.put(ctx, ctx.IDENTIFIER().getText() + Common.DELIMITER);
    }

    @Override
    public void enterQualifiedIdent(GoParser.QualifiedIdentContext ctx) {

    }

    @Override
    public void exitQualifiedIdent(GoParser.QualifiedIdentContext ctx) {

    }

    @Override
    public void enterCompositeLit(GoParser.CompositeLitContext ctx) {

    }

    @Override
    public void exitCompositeLit(GoParser.CompositeLitContext ctx) {

    }

    @Override
    public void enterLiteralType(GoParser.LiteralTypeContext ctx) {

    }

    @Override
    public void exitLiteralType(GoParser.LiteralTypeContext ctx) {

    }

    @Override
    public void enterLiteralValue(GoParser.LiteralValueContext ctx) {

    }

    @Override
    public void exitLiteralValue(GoParser.LiteralValueContext ctx) {

    }

    @Override
    public void enterElementList(GoParser.ElementListContext ctx) {

    }

    @Override
    public void exitElementList(GoParser.ElementListContext ctx) {

    }

    @Override
    public void enterKeyedElement(GoParser.KeyedElementContext ctx) {

    }

    @Override
    public void exitKeyedElement(GoParser.KeyedElementContext ctx) {

    }

    @Override
    public void enterKey(GoParser.KeyContext ctx) {

    }

    @Override
    public void exitKey(GoParser.KeyContext ctx) {

    }

    @Override
    public void enterElement(GoParser.ElementContext ctx) {

    }

    @Override
    public void exitElement(GoParser.ElementContext ctx) {

    }

    @Override
    public void enterStructType(GoParser.StructTypeContext ctx) {

    }

    @Override
    public void exitStructType(GoParser.StructTypeContext ctx) {

    }

    @Override
    public void enterFieldDecl(GoParser.FieldDeclContext ctx) {

    }

    @Override
    public void exitFieldDecl(GoParser.FieldDeclContext ctx) {

    }

    @Override
    public void enterString_(GoParser.String_Context ctx) {

    }

    @Override
    public void exitString_(GoParser.String_Context ctx) {

    }

    @Override
    public void enterEmbeddedField(GoParser.EmbeddedFieldContext ctx) {

    }

    @Override
    public void exitEmbeddedField(GoParser.EmbeddedFieldContext ctx) {

    }

    @Override
    public void enterFunctionLit(GoParser.FunctionLitContext ctx) {

    }

    @Override
    public void exitFunctionLit(GoParser.FunctionLitContext ctx) {

    }

    @Override
    public void enterIndex(GoParser.IndexContext ctx) {

    }

    @Override
    public void exitIndex(GoParser.IndexContext ctx) {

    }

    @Override
    public void enterSlice_(GoParser.Slice_Context ctx) {

    }

    @Override
    public void exitSlice_(GoParser.Slice_Context ctx) {

    }

    @Override
    public void enterTypeAssertion(GoParser.TypeAssertionContext ctx) {

    }

    @Override
    public void exitTypeAssertion(GoParser.TypeAssertionContext ctx) {

    }

    @Override
    public void enterArguments(GoParser.ArgumentsContext ctx) {

    }

    @Override
    public void exitArguments(GoParser.ArgumentsContext ctx) {
        if (ctx.expressionList() != null) {
            values.put(ctx, values.get(ctx.expressionList()));
        }
    }

    @Override
    public void enterMethodExpr(GoParser.MethodExprContext ctx) {

    }

    @Override
    public void exitMethodExpr(GoParser.MethodExprContext ctx) {

    }

    @Override
    public void enterReceiverType(GoParser.ReceiverTypeContext ctx) {

    }

    @Override
    public void exitReceiverType(GoParser.ReceiverTypeContext ctx) {

    }

    @Override
    public void enterEoss(GoParser.EossContext ctx) {

    }

    @Override
    public void exitEoss(GoParser.EossContext ctx) {

    }

    @Override
    public void visitTerminal(TerminalNode terminalNode) {

    }

    @Override
    public void visitErrorNode(ErrorNode errorNode) {

    }

    @Override
    public void enterEveryRule(ParserRuleContext parserRuleContext) {

    }

    @Override
    public void exitEveryRule(ParserRuleContext parserRuleContext) {

    }
}
